package com.vpt;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;

public class Setup {
	static volatile boolean finished = false;
	static CountDownLatch latch=new CountDownLatch(2);

	public static void main(String[] args) throws InterruptedException {
		BlockingQueue<Integer> q = new LinkedBlockingQueue<>();
		Map<Integer, Integer> primerMap = new HashMap<>();
		

		Producer p = new Producer(q);
		Consumer c1 = new Consumer(q, primerMap);
		Consumer c2 = new Consumer(q, primerMap);

		new Thread(p).start();
		new Thread(c1).start();
		new Thread(c2).start();

		latch.await();
		System.out.println(primerMap);
			
	}
}

class Producer implements Runnable {
	private final BlockingQueue<Integer> queue;
	private final Random r = new Random();

	Producer(BlockingQueue<Integer> q) {
		queue = q;
	}

	@Override
	public void run() {
		int count = 0;
		try {
			while (true) {
				queue.put(produce());
				count++;
				if (count >= 100000) {
					Setup.finished = true;
					return;
				}
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}

	Integer produce() {
		return r.nextInt(1000);
	}
}

class Consumer implements Runnable {
	private final BlockingQueue<Integer> queue;
	private final Map<Integer, Integer> primeMap;
	private static final Object lock = new Object();

	Consumer(BlockingQueue<Integer> q, Map<Integer, Integer> map) {
		queue = q;
		primeMap = map;
	}

	@Override
	public void run() {
		
		try {
			while (true) {
				consume(queue.take());
				if (Setup.finished) {
					Setup.latch.countDown();
					return;
				}
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	void consume(Integer o) {
		System.out.println("source Integer is:" + o);
		if (Prime.isPrimer(o)) {
			synchronized (lock) {
				if (primeMap.containsKey(o)) {
					primeMap.put(o, primeMap.get(o) + 1);
				} else {
					primeMap.put(o, 1);
				}
			}
		}
	}

}

final class Prime {
	static boolean isPrimer(int source) {
		int range = (int) Math.sqrt(source) + 1;
		for (int i = 2; i < range; i++) {
			if (source % i == 0) {
				return false;
			}
		}

		return true;
	}
}
